﻿#include "CoreSpcn.h"
#include "common.h"

extern CCoreSPCN *pSPCN;

///////////////////////////////////////////////////////////////////////////
double sqrt2PI = sqrt(2*PI);
CCoreSPCN::CCoreSPCN() 
: N_Perf(0),stopPerf(false),m_Size(0)
{}
///////////////////////////////////////////////////////////////////////////
CCoreSPCN::~CCoreSPCN()
{}
///////////////////////////////////////////////////////////////////////////
void CCoreSPCN::Init()
{
	srand(time(0));
	pCurrentDistLaw = &CCoreSPCN::distExp;
	//currLawName.clear();
	currLawName = "Exponential";
	currLaw = lawExp;
	m_Size = 3;
	N_Perf = 3;
	u = 0.0;
	v = 1.0;
	eps = 1.0;
}
///////////////////////////////////////////////////////////////////////////
// производится подготовка данных и выбор параметров выполнения
int CCoreSPCN::run()
{
	std::map<int,std::vector<double> >::iterator _it;
	int i = 0;
	_it = eigVal.begin();
	while( _it != eigVal.end() ){
		eigVal[i++].clear();
		eigVal.erase(_it++);
	}

	CondNum.clear();

	if (setting.usingMemory)
		_dataMtr.clear();

	stopPerf = false;

	// если надо создать поток
	if (setting.usingThreading)
	{
		//HANDLE hThread;
		//unsigned threadID;
		//hThread = (HANDLE)_beginthreadex( NULL, 0,&this->Thread_Process, NULL, NULL, &threadID);
		//WaitForSingleObject( hThread, INFINITE );
		//CloseHandle( hThread );
		_beginthreadex( NULL, 0,&this->Thread_Process, NULL, NULL, NULL);
	}
	else
	{
		PerformsCN();
	}

return 0;
}
///////////////////////////////////////////////////////////////////////////
// основной цикл вычислений
int CCoreSPCN::PerformsCN()
{		
	if (setting.usingDisk && !setting.isImportMtr)
		outDataFile.open("data.dat", std::ios::binary | std::ios::out);

	CMatrix eigVec(m_Size,m_Size);
	CMatrix _Mtr(m_Size,m_Size);
	_Mtr.fill(0);

	for(id_Perform = 0; id_Perform != N_Perf; ++id_Perform)
	{
		if(stopPerf) break;
		// tresh 
		eigVec.fill(0);
		// fill vector
		for (int i = 0; i < m_Size; i++)
			eigVal[id_Perform].push_back(0);

		// сотворение матриц :)
		createMtr(_Mtr);
		// если для хранения данных используется файл
		// и в нем нет импортированных данных
		if (setting.usingDisk && !setting.isImportMtr)
			outMtrToBinaryFile(_Mtr);					// TODO: /test/	Done!
		// ...
		if (setting.usingMemory && !setting.isImportMtr)
			_dataMtr.push_back(_Mtr);

		// если необходимо выводить форматированные матрицы в файл
		if (setting.isOutMtrInEachFile)
			outMtrFor_MatLab(_Mtr);

		// нахождение собственных значений по методу Якоби
		Jacobi( m_Size,_Mtr, eigVal[id_Perform], eigVec );
		// вычисление числа обусловленности матрицы
		CondPerform();
	}

	if(setting.usingDisk && !setting.isImportMtr)
		outDataFile.close();

	if(setting.isOutMtrInOneFile)
		outAllMatrixToFile();

	if (setting.isOutCond)
		exportCondNum();

	setting.isImportMtr = false;

return 0;
}
///////////////////////////////////////////////////////////////////////////
// получение корреляционной матрицы в соответствии с настройками
void CCoreSPCN::createMtr(CMatrix& m)
{	// если используются импортированные данные матриц из файла
	if (setting.isImportMtr)
	{	// если для хранения матриц используется диск
		if (setting.usingDisk)
		{
			readMtrFromFile(id_Perform,m);
		}
		// если для хранения матриц используется память
		if (setting.usingMemory)
		{
			readMtrFromMemory(id_Perform,m);
		}
	}// если надо генерировать матрицу
	else
	{
		for(int i = 0; i < m.getCol(); i++)
		{
			for(int j = 0; j < m.getRow(); j++)
			{
				// интервал значений по закону распределения
				m[i][j] = (this->*pCurrentDistLaw)();
				m[j][i] = m[i][j];
			}
			m[i][i] = 1;
		}
	}
}
//***********************************************************************//
//
//  Метод Якоби нахождения собственных значений и собственных векторов
//                       для симметричных матриц
//    Входные данные:
//        n - размерность матрицы
//        a - исходная матрица. В процессе работы наддиагональные элементы
//            будут изменены, но их легко восстановить по поддиагональным
//    Выходные данные:
//        d - массив собственных значений
//        v - массив собственных векторов
//***********************************************************************//
void CCoreSPCN::Jacobi( const uint n, double * const * a, vector<double>& eV, double * const * v )
{
	if ( n == 0 ) return;
	double * b = new double[n+n];
	double * z = b + n;
	uint i, j;
	for(i=0; i<n; i++){
		z[i] = 0.;
		b[i] = eV[i] = a[i][i];
		for(j = 0; j<n; j++){
			v[i][j] = i == j ? 1. : 0.;
		}
	}
	for(i=0; i<50; i++){
		// sm - сумма модулей всех всех над диагональных элементов
		double sm = 0.;		
		uint p, q;
		for ( p = 0; p < n - 1; p++ ){
			for ( q = p + 1; q < n; q++ ){
				sm += fabs ( a[p][q] );
			}
		}
		if(sm==0) break;
		const double tresh = i < 3 ? 0.2 * sm / ( n*n ) : 0.;
		for ( p = 0; p < n - 1; p++ ){
			for ( q = p + 1; q < n; q++ ){
				const double g = 1e12 * fabs ( a[p][q] );
				if ( i >= 3 && fabs ( eV[p] ) > g && fabs ( eV[q] ) > g )
					a[p][q] = 0.;
				else
					if(fabs(a[p][q]) > tresh){
						const double theta = 0.5 * (eV[q] - eV[p]) / a[p][q];
						float t = 1. / (fabs(theta) + sqrt(1.+theta*theta));
						if (theta < 0) t = - t;
						// вычисление тангенса угла врвщения
						const double c = 1. / sqrt (1. + t*t);
						const double s = t * c;
						const double tau = s / ( 1. + c );
						const double h = t * a[p][q];
						z[p] -= h;
						z[q] += h;
						eV[p] -= h;
						eV[q] += h;
						a[p][q] = 0.;
						for (j=0; j<p; j++){
							const double g = a[j][p];
							const double h = a[j][q];
							a[j][p] = g - s * ( h + g * tau );
							a[j][q] = h + s * ( g - h * tau );
						}
						for(j=p+1; j<q; j++){
							const double g = a[p][j];
							const double h = a[j][q];
							a[p][j] = g - s * ( h + g * tau );
							a[j][q] = h + s * ( g - h * tau );
						}
						for(j=q+1; j<n; j++){
							const double g = a[p][j];
							const double h = a[q][j];
							a[p][j] = g - s * ( h + g * tau );
							a[q][j] = h + s * ( g - h * tau );
						}
						for(j=0; j<n; j++){
							const double g = v[j][p];
							const double h = v[j][q];
							v[j][p] = g - s * ( h + g * tau );
							v[j][q] = h + s * ( g - h * tau );
						}
					}
			}
		}
		for(p = 0; p<n; p++){
			eV[p] = (b[p] += z[p]);
			z[p] = 0.;
		}
	}
	delete[] b;
}
///////////////////////////////////////////////////////////////////////////
// вычисление числа обусловленности abs(maxEigval/minEigval)
void CCoreSPCN::CondPerform()
{
	double max,min;
	double tmpCond = 0;
	// находим максимум/минимум в выборке
	max = min = fabs(eigVal[id_Perform].at(0));
	for (int i=0; i < m_Size; i++){
		if (max < fabs(eigVal[id_Perform].at(i))) 
			max = fabs(eigVal[id_Perform].at(i));
		if (min > fabs(eigVal[id_Perform].at(i))) 
			min = fabs(eigVal[id_Perform].at(i));
	}
	tmpCond = max / min;
	val_Id vi;
	vi.val = tmpCond;
	int id = id_Perform;
	vi.id = id + 1;
	CondNum.push_back(vi);
}
///////////////////////////////////////////////////////////////////////////
// прекращение серии вычислений
int CCoreSPCN::StopPerforms()
{
	stopPerf = true;
	id_Perform = 0;
return 0;
}
///////////////////////////////////////////////////////////////////////////
// возвращает данные в интервале [0..1]
double unifRand()
{
	return rand() / double(RAND_MAX);
}
///////////////////////////////////////////////////////////////////////////
// Экспоненциальное распределение
double CCoreSPCN::distExp()
{
	double x = 1 - exp( -1 * ( unifRand() ));
return x;
}
///////////////////////////////////////////////////////////////////////////
// Распределение Коши
double CCoreSPCN::distCauchy()
{
	double x = 0.5 + atan(( unifRand() - u ) / v ) / PI;
return x;
}
///////////////////////////////////////////////////////////////////////////
// Нормальное распределение
double CCoreSPCN::distNormal()
{
	double x = (1/(sqrt2PI*v))*exp(-(pow(unifRand()-u,2)/(2*(pow(v,2)))));
return x;
	//sqrt(-1.0 * log(pR->unifRand())) * cos(2.0 * PI * pR->unifRand());
}
///////////////////////////////////////////////////////////////////////////
// Логнормальное распределение
double CCoreSPCN::distLognorm()
{
	double x = log((( exp(distNormal()) - u ) / v ));
return x;
}
///////////////////////////////////////////////////////////////////////////
// Равномерное распределение
double CCoreSPCN::distUniform()	//TODO: check!
{
return unifRand();
}
///////////////////////////////////////////////////////////////////////////
// Выбор закона распределения
void CCoreSPCN::setDistLaw(int law, ...)
{
	switch (law){
	case lawExp: {
		pCurrentDistLaw = &CCoreSPCN::distExp;
		currLawName = "Exponential";
		currLaw = lawExp;
				 } break;
	case lawNormal: {
		pCurrentDistLaw = &CCoreSPCN::distNormal;
		currLawName = "Normal";
		currLaw = lawNormal;
					} break;
	case lawCauchy: {
		pCurrentDistLaw = &CCoreSPCN::distCauchy;
		currLawName = "Cauchy";
		currLaw = lawCauchy;
					} break;
	case lawLognormal: {
		pCurrentDistLaw = &CCoreSPCN::distLognorm;
		currLawName = "Lognormal";
		currLaw = lawLognormal;
					   } break;
	case lawUniform: {
		pCurrentDistLaw = &CCoreSPCN::distUniform;
		currLawName = "Uniform";
		currLaw = lawUniform;
					 } break;
	default: {
		pCurrentDistLaw = &CCoreSPCN::distNormal;
		currLawName = "Normal";
		currLaw = lawNormal;
			 } break;
	}
}
///////////////////////////////////////////////////////////////////////////
// выводит число обусловленности в файл
int CCoreSPCN::exportCondNum()
{
	char buffFileMtr[256]; 
	memset( buffFileMtr, 0, sizeof(buffFileMtr) );
	sprintf(buffFileMtr,"../Result/CondNumber_%s_n%d_%dx%d.txt", currLawName,N_Perf,m_Size,m_Size);

	std::ofstream outF(buffFileMtr, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	outF <<"\n# Condition number correlation matrix:"<<" 1-"<<N_Perf<<"\n";
	outF <<"# Distribution law:	"<<"< "<<currLawName<<" >\n";
	outF <<"# Correlation matrix:	"<<"< "<<m_Size<<"x"<<m_Size<<" >\n\n";
	
	int i=1;
	std::vector<val_Id>::iterator it;
	for(it = CondNum.begin(); it != CondNum.end(); it++){
		outF<<"Matrix < "<<i++<<" > Cond =	"<<it->val<<std::endl;
	}
	//memset( buffFileMtr, 0, sizeof(buffFileMtr) );
	outF.close();
return 0;
}
///////////////////////////////////////////////////////////////////////////
// экспортирует число обусловленности в файл
int CCoreSPCN::exportCondNum(char* nameFile)
{
	std::ofstream outF(nameFile, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	outF <<"\n# Condition number correlation matrix:"<<" 1-"<<N_Perf<<"\n";
	outF <<"# Distribution law:	"<<"< "<<currLawName<<" >\n";
	outF <<"# Correlation matrix:	"<<"< "<<m_Size<<"x"<<m_Size<<" >\n\n";

	int i = 1;
	std::vector<val_Id>::iterator it;
	for(it = CondNum.begin(); it != CondNum.end(); it++){
		outF<<"Matrix < "<<i++<<" > Cond =	"<<it->val<<std::endl;
	}
	outF.close();
return 0;
}
// экспортировать для MatLab
int CCoreSPCN::exportCondNumToMatLab(char* nameFile)
{
	std::ofstream outF(nameFile, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	outF <<"\n CondNum"<<" = ["<<"\n";
	int i = 1;
	std::vector<val_Id>::iterator it;
	for(it = CondNum.begin(); it != CondNum.end(); it++){
		outF<<" "<<it->val<<std::endl;
	}
	outF << " ]";
	outF.close();
	return 0;
}
///////////////////////////////////////////////////////////////////////////
// Выводит все матрицы в один текстовый файл. Данные разделены пробелом 
// матрицы новой строкой
int CCoreSPCN::outAllMatrixToFile()
{	
	int MtrSize = (m_Size * m_Size);
	// открываем бинарный файл для чтения
	ifstream instrm ("data.dat", std::ios::binary | std::ios::in);
	double tmpr,pos;
	int m=1;
	char nameFile[256];
	memset( nameFile, 0, sizeof(nameFile) );
	sprintf(nameFile, "../Result/AllMatr_n%d_%dx%d_%s.txt", N_Perf,m_Size,m_Size,currLawName);
	// создаем текстовый файл для записи
	std::ofstream outF(nameFile, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	while(!instrm.eof())
	{
		outF<<" # Matrix < "<<m++<<" >\n";
		for (int i = 0; i < m_Size; ++i)
		{
			for (int j = 0; j < m_Size; ++j)
			{
				instrm.read((char *)&tmpr, sizeof(tmpr));
				outF<<tmpr<<"	";
			}
			outF<<"\n";
		}
		outF<<"\n";
	}
	outF.close();
	instrm.close();
return 0;
}
///////////////////////////////////////////////////////////////////////////
// Экспортирует все матрицы в один текстовый файл.
int CCoreSPCN::outAllMatrixToFile(char* nameFile)
{	
	int MtrSize = (m_Size * m_Size);
	// открываем бинарный файл для чтения
	ifstream instrm ("data.dat", std::ios::binary | std::ios::in);
	double tmpr,pos;
	int m = 1;
	// создаем текстовый файл для записи
	std::ofstream outF(nameFile, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	while(!instrm.eof())
	{
		outF<<" # Matrix < "<<m++<<" >\n";
		for (int i = 0; i < m_Size; ++i)
		{
			for (int j = 0; j < m_Size; ++j)
			{
				instrm.read((char *)&tmpr, sizeof(tmpr));
				outF<<tmpr<<"	";
			}
			outF<<"\n";
		}
		outF<<"\n";
	}
	outF.close();
	instrm.close();
return 0;
}
///////////////////////////////////////////////////////////////////////////
// вывод матрицы в бинарный файл
void CCoreSPCN::outMtrToBinaryFile(CMatrix m)
{
	int sd =  sizeof(double);
	if(outDataFile.is_open())
	{
		for (int i = 0; i < m.getCol(); i++)
		{
			for (int j = 0; j < m.getRow(); j++)
			{
				outDataFile.write((char *)&m[i][j], sd); 
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////
// Выводит матрицу в файл для проверки в MatLab
void CCoreSPCN::outMtrFor_MatLab(CMatrix m)
{
	char buffFileMtr[256]; 
	memset( buffFileMtr, 0, sizeof(buffFileMtr) );
	sprintf(buffFileMtr, "../Result/KorellMatr#_%d_#.txt", id_Perform+1);
	std::ofstream outF(buffFileMtr, ios::out | ios::trunc);
	outF.setf(ios::fixed);

	outF <<"\n# Distribution law:	"<<"< "<<currLawName<<" >\n";
	outF <<"# Correlation matrix:	"<<"< "<<m.getCol()<<"x"<<m.getRow()<<" >\n";
	outF <<"# Current Exp. :	"<<"< "<<id_Perform+1<<" >"<<std::endl;
	outF <<std::endl<<"A "<<"= ["<<endl;
	for (int i = 0; i < m.getCol(); i++)
	{
		for (int j = 0; j < m.getRow(); j++)
		{
			if (j == m.getRow()-1) outF<< m[i][j]<< ";"<< endl;
			else
				outF << m[i][j]<<"   ";
		}
	}
	outF << "]" << endl;

	outF.close();
}
///////////////////////////////////////////////////////////////////////////
// просто выводит форматированную матрицу в окно консоли
void CCoreSPCN::outMtrToConsole(CMatrix m)
{
	std::cout <<endl;
	for(int x = 0; x < m.getCol(); x++)
	{
		for(int y = 0; y < m.getRow(); y++)
		{
			printf(" |% 10f |", m[x][y]); 
		}
		std::cout << endl;
	}
	std::cout << endl;
}
///////////////////////////////////////////////////////////////////////////
// чтение указанной матрицы 'm' из памяти по ее ID - 'n'
void CCoreSPCN::readMtrFromMemory( int n, CMatrix& m )
{
	for(int i = 0; i < m.getCol(); i++)
	{
		for(int j = 0; j < m.getRow(); j++)
		{
			m[i][j] = _dataMtr[n][i][j];
		}
	}
}
///////////////////////////////////////////////////////////////////////////
// читает матрицу из бинарного файла n-номер матрицы
void CCoreSPCN::readMtrFromFile(int n, CMatrix& m)
{
	int MtrSize = (m_Size * m_Size);
	ifstream instrm ("data.dat", std::ios::binary | std::ios::in);
	double tmpr,pos;
	// открываем файл для чтения 
	if (n!=0){
		// определяем смещения в файле(*.dat) для матрицы 
		double sd;
		int offset = (sizeof(sd) * MtrSize) * n;
		instrm.seekg (offset);
	}
	instrm.read((char *)*m, (sizeof(tmpr) * MtrSize));
	instrm.close();
}
///////////////////////////////////////////////////////////////////////////
// импортирует данные 'матриц' из текстового файла в программу
// (числа разделены табуляцией, матрицы должны быть квадратными)
int CCoreSPCN::importMatix(char *nameFile)
{
	std::ifstream inF(nameFile, ios_base::in);
	std::vector<std::string> allStr;
	int row,col;
	if (!inF.is_open()){
		cout << endl << "Error !";	// TODO: /err log/
	}
	string line;
	getline(inF,line);
	size_t _dimMtr;
	// опредяляем размерность матрицы по кол-ву эл-тов в 1 строке
	_dimMtr = count(line.begin(),line.end(),'	') + 1;
	inF.seekg(ios::beg);	

	size_t len = 0, _nMtr = 0, cout_str = 0;
	// количество строк в файле
	while (getline(inF,line))
	{
		int len_str = count(line.begin(),line.end(),'	') + 1;
		// если текущая строка эквивалентна первой
		// значит это строка матрицы
		if (len_str == _dimMtr)	
		{
			cout_str++;	
			allStr.push_back(line);
		}
	}
	// тест на корректность данных
	if (fmodf(cout_str,_dimMtr) != 0)
	{
		cout<<"Import File Wrong!"<<endl;
		return -1;
	}
	// количество матриц
	_nMtr = cout_str / _dimMtr;
	// устанавливаем параметры для вычислений
	N_Perf = _nMtr;
	m_Size = _dimMtr;
	CondNum.clear();
	// fill CondNumber vector values
	for (int i = 0; i < _nMtr; i++){
		val_Id vi;
		CondNum.push_back(vi);
	}
		
	// если в используется дисковая система
	if (setting.usingDisk)
	{
		clearDataFile();
		outDataFile.open("data.dat", std::ios::binary | std::ios::out);
		
		int _itMtr = 0;
		size_t i = 0, j = 0;
		double tVal = 0;
		while ( _itMtr < _nMtr )
		{
			CMatrix m(_dimMtr,_dimMtr);
			for ( i = 0; i < _dimMtr; i++)
			{
				istringstream stream(allStr.at(i));
				for (j = 0; j < _dimMtr; j++)
				{
					stream >> tVal;			// TODO: check!/fix
					m[i][j] = tVal;
				}
			}
			outMtrToBinaryFile(m);
			_itMtr++;
		}
		outDataFile.close();
	}
	// если используется память
	if (setting.usingMemory)
	{
		_dataMtr.clear();
		int _itMtr = 0;
		size_t i = 0, j = 0;
		while ( _itMtr < _nMtr )
		{
			CMatrix m(_dimMtr,_dimMtr);
			for ( i = 0; i < m.getCol(); i++)
			{
				istringstream stream(allStr.at(i));
				for (j = 0; j < m.getRow(); j++)
					stream >> m[i][j];
			}
			_dataMtr.push_back(m);
			_itMtr++;
		}
	}
	inF.close();
return  0;
}
///////////////////////////////////////////////////////////////////////////
// сохранение результатов вычислений
void CCoreSPCN::saveResult(char* nameFile)
{
	if (setting.usingMemory)
	{
		ofstream dataFile;
		dataFile.open("data.dat", std::ios::binary | std::ios::out);
		double tmpVal;
		int itM = 0;
		while(itM != N_Perf)
		{
			dataFile.write((char *)&_dataMtr[itM], (sizeof(tmpVal) * m_Size) * 2);
			itM++;
		}
		dataFile.close();
	}
	ifstream dataFile;
	dataFile.open("data.dat", std::ios::binary | std::ios::in);
	double tmpr,pos;

	std::ofstream resultFile;
	resultFile.open(nameFile, std::ios::binary | std::ios::out);

	// сохраняем количество экспирементов
	resultFile.write((char *)&N_Perf, sizeof(int)); 
	// сохраняем размерность матрицы
	resultFile.write((char *)&m_Size, sizeof(int)); 
	resultFile.write((char *)&currLaw, sizeof(int)); 
	// сохраняем имя текущего закона распределения
	long size =  (sizeof(char)*40);
	resultFile.write(currLawName,size); 

	// сохраняем матрицы 
	int _n = 0;
	double *blockMtr;
	blockMtr = new double[m_Size * m_Size];
	long sizeMtr = (m_Size * m_Size) * (sizeof(*blockMtr));	// TODO: /modif/
	while ( _n < N_Perf )
	{
		dataFile.read((char *)blockMtr, sizeMtr);
		resultFile.write((char *)blockMtr, sizeMtr); 
		_n++;
	}
	delete[] blockMtr;

	dataFile.close();

	//std::vector<val_Id>::iterator it;
	// сохраняем число обусловленности
	long sizeCond = sizeof(val_Id);
	for(int i = 0; i != N_Perf; i++){	// TODO: /modif/optimization/!!!
		val_Id _tmpC = CondNum.at(i);
		resultFile.write((char *)&_tmpC,  sizeCond);
	}
	resultFile.close();
}
///////////////////////////////////////////////////////////////////////////
// загрузка данных
void CCoreSPCN::loadResult(char *nameFile)
{
	// очищаем все данные
	long i = 0;
	std::map<int,std::vector<double> >::iterator it;
	it = eigVal.begin();
	while( it != eigVal.end() ){	
		eigVal[i++].clear();
		eigVal.erase(it++);
	}

	clearDataFile();

	ofstream dataFile;
	// открываем файлы для записи/чтения
	dataFile.open("data.dat", std::ios::binary | std::ios::out);
	double tmpr,pos;

	std::ifstream resultFile;
	resultFile.open(nameFile, std::ios::binary | std::ios::in);

	int _nExp = 0,_mSize = 0,_dl = 0;
	// считываем количество вычислений
	resultFile.read((char *)&_nExp, sizeof(int));
	N_Perf = _nExp;
	
	// считываем размерность матриц
	resultFile.read((char *)&_mSize, sizeof(int));
	m_Size = _mSize;
	// считываем ID закона распределения 
	resultFile.read((char *)&_dl, sizeof(_dl)); 
	currLaw = (distLaws)_dl;
	// считываем имя закона распределения
	char *strFuck = new char[40];
	long size =  (sizeof(char) * 40);
	resultFile.read(strFuck, size); 
	currLawName = strFuck;
	delete[] strFuck;

	// переписываем матрицы из resultFile->dataFile
	int _n = 0;
	double *blockMtr = new double[m_Size * m_Size];
	long sizeMtr = (m_Size * m_Size) * (sizeof (*blockMtr));// TODO: /modif/
	while( _n < N_Perf )
	{
		resultFile.read((char *)blockMtr,  sizeMtr);
		dataFile.write((char *)blockMtr,  sizeMtr);
		_n++;
	}
	delete[] blockMtr;

	CondNum.clear();
	//long sizeCond = sizeof(val_Id) * N_Perf;
	long sizeCond = sizeof(val_Id);
	for(int i = 0; i < N_Perf; i++)	// TODO: /modif/optimization/!!!
	{	
		val_Id _tmpC;
		resultFile.read((char *)&_tmpC, sizeCond);
		CondNum.push_back(_tmpC);
	}

	dataFile.close();
	resultFile.close();
}
///////////////////////////////////////////////////////////////////////////
// удаляем все сгенерированные файлы
// return 1 - если неудалось удалить файлы
// return 0 - успешное удаление
int CCoreSPCN::clearAllDataFile()	// TODO: /fix/implement
{
	char buffFileMtr[40]; 

	if( remove( "../Result/CondNumber.txt" ) != 0 )
	{
		return 1;
	}
	else
	{
		for (int i = 0;i != N_Perf; i++)
		{
			memset( buffFileMtr, 0, sizeof(buffFileMtr) );
			sprintf(buffFileMtr, "../Result/KorellMatr#_%d_#.txt", i);
			remove(	buffFileMtr	);
		}
	}
return 0;
}
///////////////////////////////////////////////////////////////////////////
// очищаем файл данных
void CCoreSPCN::clearDataFile()
{
	std::ofstream outFbin;
	outFbin.open("data.dat", std::ios::binary | std::ios::ate);
	outFbin.close();
}
///////////////////////////////////////////////////////////////////////////
// мин/макс/сумма/среднее/частоты/относительные частоты/распределение/
void CCoreSPCN::CondAnаliz( int n )	// TODO: /modif/
{
	_statistic.minCond = _statistic.maxCond = CondNum.at(0).val;
	_statistic.sumCond = _statistic.avrgCond = NULL;
	for (int i = 0; i < N_Perf; i++)
	{
		if (_statistic.maxCond < CondNum.at(i).val) 
			_statistic.maxCond = CondNum.at(i).val;
		if (_statistic.minCond > CondNum.at(i).val) 
			_statistic.minCond = CondNum.at(i).val;

		_statistic.sumCond += CondNum.at(i).val;
	}
	_statistic.avrgCond = (_statistic.sumCond / N_Perf);

	int freq;
	val_Id vi;
	if (!_statistic.CondStat.empty())
		_statistic.CondStat.clear();
	
	sortCondDown();
	// считаем частоты вхождений числа в массив
	for(long i = 0,j = 0;;)		// TODO: review/fix
	{
		freq = 1;	// частота вхождений числа по умолчанию
		
		// считаем частоты отбросив дробную часть
		while( ((int)CondNum.at(i).val - (int)CondNum.at(i+1).val) == 0 )
		{
			freq++;	//
			i++;
			if(i == (N_Perf - 1) )	// если i потберется к границе массива в цикле
				break;
		}
		// считае частоты с указаной точностью
		//while(fabs(CondNum.at(i).val - CondNum.at(i+1).val) < eps )
		//{
		//	frec++;	//
		//	i++;
		//}
		//} 
		vi.id = freq;
		vi.val = CondNum.at(i).val;
		_statistic.CondStat[j++] = vi;
		i++;
		if(i >= (N_Perf - 1) )
			break;
	}
	//int size = 0;
	//size = _statistic.CondStat.size();
	//for(long i = 0;i <= size; i++)
	//{
	//	distFunk tmp;
	//	tmp.freq = _statistic.CondStat[i].id / N_Perf;
	//	tmp.val = _statistic.CondStat[i].val;
	//	_statistic.CondDistFunction.push_back(tmp);
	//}
	//unsortCond();
	//int i = 4; 
}
///////////////////////////////////////////////////////////////////////////
bool unsort (const val_Id& left, const val_Id& right) 
{
	return left.id > right.id;
}
///////////////////////////////////////////////////////////////////////////
void CCoreSPCN::unsortCond()
{
	std::sort(CondNum.rbegin(),CondNum.rend(),&unsort);
}
///////////////////////////////////////////////////////////////////////////
void CCoreSPCN::sortCondUP()
{
	std::sort(CondNum.rbegin(),CondNum.rend());
}
///////////////////////////////////////////////////////////////////////////
void CCoreSPCN::sortCondDown()
{
	std::sort(CondNum.begin(),CondNum.end());
}
///////////////////////////////////////////////////////////////////////////
unsigned WINAPI CCoreSPCN::Thread_Process(void* pArguments)
{	// инициализация рандома в потоке
	Sleep(rand() % 100);
	srand((unsigned)GetTickCount() + GetCurrentThreadId() * time(0));
	// запуск вычислений в потоке
	pSPCN->PerformsCN();
	// завершить поток
	_endthreadex( 0 );
return 0;
}